package com.kymatrix.kycarbon.xsmd.system.server.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kymatrix.kycarbon.xsmd.system.server.dao.ModuleMapper;
import com.kymatrix.kycarbon.xsmd.system.server.dao.RoleModuleMapper;
import com.kymatrix.kycarbon.xsmd.system.server.dao.UserMapper;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.ModuleEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.RoleEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.RoleModuleRelationEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.UserEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.UserRoleRelationEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.InsertUserReq;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.ListQueryUserResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.PageQueryUserReq;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.PageQueryUserResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.QueryUserAuthResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.QueryUserResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.UpdateUserPwdReq;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.user.UpdateUserReq;
import com.kymatrix.kycarbon.xsmd.system.server.service.IRoleService;
import com.kymatrix.kycarbon.xsmd.system.server.service.IUserRoleRelationService;
import com.kymatrix.kycarbon.xsmd.system.server.service.IUserService;
import com.kymatrix.kycarbon.xsmd.common.constants.Constant;
import com.kymatrix.kycarbon.xsmd.common.enums.ModuleTypeEnum;
import com.kymatrix.kycarbon.xsmd.common.exception.BusinessException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
@Primary
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements IUserService {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private IRoleService roleService;

    @Resource
    private RoleModuleMapper roleModuleMapper;

    @Resource
    private IUserRoleRelationService userRoleRelationService;
    @Resource
    private ModuleMapper moduleMapper;

    private String emptyUser = "用户不存在";


    @Override
    public UserEntity getByUserName(String username) {
        return this.baseMapper.selectByUsername(username);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public String save(InsertUserReq req) {
        UserEntity entity = this.baseMapper.selectByUsername(req.getUsername());
        if (entity != null) {
            throw new BusinessException("用户名重复");
        }
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(req.getUsername());
        userEntity.setPassword(passwordEncoder.encode(req.getPassword()));
        userEntity.setPhone(req.getPhone());
        userEntity.setEmail(req.getEmail());
        this.baseMapper.insert(userEntity);
        insertRoleRelations(req.getRoleIdList(), userEntity);
        return userEntity.getId();
    }

    private void insertRoleRelations(List<String> roleIdList, UserEntity userEntity) {
        for (String roleId : roleIdList) {
            if (this.roleService.getById(roleId) == null) {
                throw new BusinessException("角色不存在");
            }
            UserRoleRelationEntity entity = new UserRoleRelationEntity();
            entity.setUserId(userEntity.getId());
            entity.setRoleId(roleId);
            this.userRoleRelationService.save(entity);
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void update(UpdateUserReq req) {

        UserEntity entity = this.baseMapper.selectByUsername(req.getUsername());
        if (entity != null && !Objects.equals(entity.getId(), req.getId())) {
            throw new BusinessException("用户名重复");
        }
        
        UserEntity userEntity = this.baseMapper.selectById(req.getId());
        if (userEntity == null) {
            throw new BusinessException(emptyUser);
        }
        userEntity.setUsername(req.getUsername());
        userEntity.setPhone(req.getPhone());
        userEntity.setEmail(req.getEmail());
        this.baseMapper.updateById(userEntity);

        userRoleRelationService.deleteByUserId(req.getId());

        insertRoleRelations(req.getRoleIdList(), userEntity);
    }

    @Override
    public QueryUserResp getUser(String id) {
        UserEntity userEntity = this.baseMapper.selectById(id);
        if (userEntity == null) {
            return null;
        }
        List<UserRoleRelationEntity> list = this.userRoleRelationService.selectByUserId(id);
        List<String> roleIds = list.stream().map(a -> a.getRoleId()).collect(Collectors.toList());
        QueryUserResp res = new QueryUserResp();
        res.setId(userEntity.getId());
        res.setUsername(userEntity.getUsername());
        res.setPhone(userEntity.getPhone());
        res.setEmail(userEntity.getEmail());
        res.setRoleIds(roleIds);
        return res;
    }



    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void editPassword(UpdateUserPwdReq req) {
        UserEntity user = this.baseMapper.selectById(req.getId());
        if (user == null) {
            throw new BusinessException(emptyUser);
        }
        user.setPassword(passwordEncoder.encode(req.getNewPassword()));
        this.baseMapper.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void deleteUser(String id) {
        UserEntity userEntity = this.baseMapper.selectById(id);
        if (userEntity == null) {
            return;
        }
        userEntity.setDeleted(Constant.DEL_FLAG_DELETE);
        this.baseMapper.updateById(userEntity);
        
        this.userRoleRelationService.deleteByUserId(id);
    }

    @Override
    public Page<PageQueryUserResp> pageQuery(PageQueryUserReq req) {
        return this.baseMapper.pageQuery(
                new Page<>(req.getCurrent(), req.getPageSize()), req.getUsername(), req.getRoleName());
    }

    @Override
    public QueryUserAuthResp auth(String id) {
        QueryUserAuthResp res = new QueryUserAuthResp();
        
        UserEntity userEntity = this.baseMapper.selectById(id);
        if (userEntity == null) {
            throw new BusinessException(emptyUser);
        }
        res.setId(userEntity.getId());
        res.setUsername(userEntity.getUsername());
        res.setPhone(userEntity.getPhone());
        res.setEmail(userEntity.getEmail());
        
        List<UserRoleRelationEntity> userRoleList = this.userRoleRelationService.selectByUserId(id);
        if (!userRoleList.isEmpty()) {
            List<String> roleIdList = userRoleList.stream().map(
                    UserRoleRelationEntity::getRoleId).collect(Collectors.toList());
            List<RoleEntity> roleList = this.roleService.selectByIds(roleIdList);
            for (RoleEntity roleEntity : roleList) {
                res.getRoleInfoList().add(new QueryUserAuthResp.RoleInfo(roleEntity.getId(), roleEntity.getName()));
            }
            List<RoleModuleRelationEntity> roleModuleList = this.roleModuleMapper.selectByRoleIds(roleIdList);
            if (!roleModuleList.isEmpty()) {
                Set<String> moduleIds = roleModuleList.stream().map(
                        RoleModuleRelationEntity::getModuleId).collect(Collectors.toSet());
                List<ModuleEntity> moduleEntities = this.moduleMapper.selectByIds(moduleIds);
                for (ModuleEntity entity : moduleEntities) {
                    res.getModuleInfoList().add(new QueryUserAuthResp.ModuleInfo(
                            entity.getId(), entity.getName(), entity.getPath(),
                            entity.getIcon(), entity.getSortNo(), entity.getParentId(), entity.getType()));
                }
                // 从moduleInfoList取排序第一个是页面的放到首位
                List<QueryUserAuthResp.ModuleInfo> moduleInfoList = res.getModuleInfoList();
                List<QueryUserAuthResp.ModuleInfo> sortRootList = moduleInfoList.stream()
                        .filter(a -> StrUtil.isEmpty(a.getParentId())).sorted(
                        Comparator.comparingInt(QueryUserAuthResp.ModuleInfo::getSortNo)).collect(Collectors.toList());
                if (!sortRootList.isEmpty()) {
                    QueryUserAuthResp.ModuleInfo root = sortRootList.get(0);
                    QueryUserAuthResp.ModuleInfo index = getIndex(root, moduleInfoList);
                    moduleInfoList.remove(index);
                    moduleInfoList.add(0, index);
                }
            }
        }
        return res;
    }

    private QueryUserAuthResp.ModuleInfo getIndex(QueryUserAuthResp.ModuleInfo root,
                                                  List<QueryUserAuthResp.ModuleInfo> moduleInfoList) {
        List<QueryUserAuthResp.ModuleInfo> childSortList = moduleInfoList.stream().filter(
            a -> Objects.equals(a.getParentId(), root.getId()) 
                        && Objects.equals(a.getType(), ModuleTypeEnum.MENU.getCode()))
                .sorted(Comparator.comparingInt(QueryUserAuthResp.ModuleInfo::getSortNo)).collect(Collectors.toList());
        if (childSortList.isEmpty()) {
            return root;
        }
        return getIndex(childSortList.get(0), moduleInfoList);
    }

    @Override
    public List<ListQueryUserResp> list(String username) {
        List<ListQueryUserResp> res = new ArrayList<>();
        List<UserEntity> userEntities = this.baseMapper.selectLikeByUsername(username);
        for (UserEntity userEntity : userEntities) {
            res.add(new ListQueryUserResp(
                    userEntity.getId(), userEntity.getUsername(), userEntity.getPhone(), userEntity.getEmail()));
        }
        return res;
    }

    @Override
    public UserEntity authenticate(String username, String password) {
        UserEntity user = this.getByUserName(username);
        if (user == null) {
            throw new BusinessException("用户或密码不正确");
        }
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new BusinessException("用户或密码不正确");
        }
        return user;
    }
}
